#include "StdAfx.hpp"
#include "ObjectCamera.hpp"

using namespace common;


////////////////////////////////////////////////////////////////////////////////
// class ObjectCamera2d

ObjectCamera2d::ObjectCamera2d()
: ScalingEnabled(true)
, KeyboardScalingEnabled(true)
, KeyboardPanEnabled(true)
, Bias(VEC2_ZERO)
, Scale(1.f)
, m_IsPanning(false)
, m_PanLastPos(VEC2_ZERO)
, ScalingSpeed(0.03f)
, FastSpeedFactor(3.f)
, KeyboardScalingSpeed(60.f)
, KeyboardPanSpeed(0.01f)
{
}

bool ObjectCamera2d::OnMouseMove( const common::VEC2 &Pos )
{
	if (m_IsPanning)
	{
		Bias += (Pos - m_PanLastPos);
		m_PanLastPos = Pos;
		return true;
	}
	else
		return false;
}

bool ObjectCamera2d::OnMouseButton( const common::VEC2 &Pos, frame::MOUSE_BUTTON Button, frame::MOUSE_ACTION Action )
{
	if (Button == frame::MOUSE_LEFT)
	{
		m_IsPanning = (Action != frame::MOUSE_UP);
		if (m_IsPanning)
			m_PanLastPos = Pos;
		return true;
	}
	else
		return false;
}

bool ObjectCamera2d::OnMouseWheel( const common::VEC2 &Pos, float Delta )
{
	if (!ScalingEnabled)
		return false;

	VEC2 unitsUnderCursor = (Pos - Bias) / Scale;

	float factor = ScalingSpeed;
	if (frame::IsKeyPressed(VK_SHIFT))
		factor *= FastSpeedFactor;
	Scale += Scale*(Delta * factor);
	if (Scale < FLT_EPSILON)
		Scale = FLT_EPSILON;

	Bias = Pos - unitsUnderCursor * Scale;

	return true;
}

void ObjectCamera2d::UnitsToScreen( common::VEC2 &out, const common::VEC2 &unitsPos ) const
{
	out = unitsPos * Scale + Bias;
}

void ObjectCamera2d::ScreenToUnits( common::VEC2 &out, const common::VEC2 &screenPos ) const
{
	out = (screenPos - Bias) / Scale;
}

void ObjectCamera2d::Update()
{
	float dt = frame::Timer1.GetDeltaTime().ToSeconds_f();

	if (KeyboardScalingEnabled && KeyboardScalingSpeed != 0.f)
	{
		int zoom = 0;
		if (frame::IsKeyPressed(VK_ADD))
			zoom++;
		if (frame::IsKeyPressed(VK_SUBTRACT))
			zoom--;
		if (zoom)
		{
			VEC2 mousePos;
			frame::GetMousePos(&mousePos);
			OnMouseWheel(mousePos, (float)zoom * KeyboardScalingSpeed * dt);
		}
	}

	if (KeyboardPanEnabled && KeyboardPanSpeed != 0.f)
	{
		POINT_ pan = POINT_ZERO;
		if (frame::IsKeyPressed(VK_LEFT))
			pan.x++;
		if (frame::IsKeyPressed(VK_RIGHT))
			pan.x--;
		if (frame::IsKeyPressed(VK_UP))
			pan.y++;
		if (frame::IsKeyPressed(VK_DOWN))
			pan.y--;
		if (pan.x)
			Bias.x += (float)pan.x * KeyboardPanSpeed * dt;
		if (pan.y)
			Bias.y += (float)pan.y * KeyboardPanSpeed * dt;
	}
}

////////////////////////////////////////////////////////////////////////////////
// class ObjectCamera3d

ObjectCamera3d::ObjectCamera3d()
: m_Camera(VEC3_ZERO, 0.f, 0.f, 7.f, 0.5f, 100.f, DegToRad(55.f), frame::GetAspectRatio())
, ZoomEnabled(true)
, PanEnabled(true)
, OrbitSpeed(0.03f)
, ZoomSpeed(0.03f)
, FastSpeedFactor(3.f)
, PanSpeed(0.01f)
, m_Mode(MODE_NONE)
, m_LastPos(VEC2_ZERO)
{

}

bool ObjectCamera3d::OnMouseMove( const common::VEC2 &Pos )
{
	if (m_Mode == MODE_ORBIT)
	{
		VEC2 angles = VEC2(m_Camera.GetAngleX(), m_Camera.GetAngleY());

		angles.y = NormalizeAngle(angles.y + (Pos.x - m_LastPos.x) * OrbitSpeed);
		angles.x = minmax(-PI_2+FLT_EPSILON, angles.x + (Pos.y - m_LastPos.y) * OrbitSpeed, PI_2-FLT_EPSILON);

		m_Camera.SetAngleX(angles.x);
		m_Camera.SetAngleY(angles.y);

		m_LastPos = Pos;
		return true;
	}
	else if (m_Mode == MODE_PAN && PanEnabled)
	{
		VEC3 pos = m_Camera.GetPos();

		float factor = PanSpeed * m_Camera.GetCameraDist();
		pos += m_Camera.GetParams().GetRightDir()  * ( (m_LastPos.x - Pos.x) * factor );
		pos += m_Camera.GetParams().GetRealUpDir() * ( (Pos.y - m_LastPos.y) * factor );

		m_Camera.SetPos(pos);

		m_LastPos = Pos;
		return true;
	}

	return false;
}

bool ObjectCamera3d::OnMouseButton( const common::VEC2 &Pos, frame::MOUSE_BUTTON Button, frame::MOUSE_ACTION Action )
{
	if (Button == frame::MOUSE_LEFT)
	{
		m_Mode = (Action == frame::MOUSE_UP) ? MODE_NONE : MODE_ORBIT;
		if (m_Mode != MODE_NONE)
			m_LastPos = Pos;
		return true;
	}
	else if (Button == frame::MOUSE_RIGHT && PanEnabled)
	{
		m_Mode = (Action == frame::MOUSE_UP) ? MODE_NONE : MODE_PAN;
		if (m_Mode != MODE_NONE)
			m_LastPos = Pos;
		return true;
	}

	return false;
}

bool ObjectCamera3d::OnMouseWheel( const common::VEC2 &Pos, float Delta )
{
	if (!ZoomEnabled)
		return false;

	float camDist = m_Camera.GetCameraDist();
	float zoomSpeed = ZoomSpeed;
	if (frame::IsKeyPressed(VK_SHIFT))
		zoomSpeed *= FastSpeedFactor;
	camDist -= camDist * (Delta * zoomSpeed);
	if (camDist < FLT_EPSILON)
		camDist = FLT_EPSILON;
	m_Camera.SetCameraDist(camDist);

	return true;
}
